/**
 * @class UI-面板-介绍面板
 * @author DuskyHuang
 * @description 根据当天主天体变化的多语言介绍面板。
 */

import { Layout, Node, _decorator } from 'cc';
import { } from 'const';
import { Mediator, ItemList } from 'cfw';
import { View, UI } from 'notifications';
import { planetary, visit } from 'proxies';
import { IIntroLineData, tag } from '../../celestial';
import { IntroLine } from '../items/intro-line';
import { LabelI18n } from '../label-i18n';
import { Belts } from '../../solar/belts';
import { Star } from '../../stellar/star';
const { ccclass, property } = _decorator;


@ccclass('cocosmos.intro-panel')
export class IntroPanel extends Mediator {

    @property(LabelI18n) public title: LabelI18n = null;
    @property(ItemList) public mainList: ItemList<IntroLine> = null;
    @property(ItemList) public cardList: ItemList<IntroLine> = null;
    @property(Node) public arrowLeft: Node = null;
    @property(Node) public arrowRight: Node = null;

    protected onLoad(): void {
        this._init();
        this._listen();
    }

    protected start(): void { }

    private _init(): void {
        this.on(UI.LANGUAGE, () => this._updateListLayout(true));
    }

    private _updateListLayout(adjust: boolean): void {
        if (adjust) {
            this.mainList.getComponentsInChildren(IntroLine).forEach(line => line.adjustHeight());
            this.cardList.getComponentsInChildren(IntroLine).forEach(line => line.adjustHeight());
        }
        this.scheduleOnce(() => {
            this.mainList.getComponent(Layout).updateLayout();
            this.cardList.getComponent(Layout).updateLayout();
        }, 0.1);
    }

    private _listen(): void {
        this.on(Transform.ZOOM_START, this.onVisitStart);
        this.on(UI.FULL_SCREEN, this.onFullScreen);
    }

    protected onEnable(): void {
        this._updateData();
    }

    protected onClickLeft(): void {
        this._showDataAt(this._showAt - 1);
    }

    protected onClickRight(): void {
        this._showDataAt(this._showAt + 1);
    }

    protected onVisitStart(): void {
        this.notify(UI.Panels.CLOSE, this.node.name);
    }

    protected onFullScreen(): void {
        if (this.node.active) this.notify(UI.Panels.CLOSE, this.node.name, true);
    }

    protected clickFold(): void {
        this.notify(UI.Panels.CLOSE, this.node.name, true);
    }

    private _updateData(): void {
        const { center: { cat, config }, inStar, inBlackhole } = visit, { centerName, unbelt } = planetary;
        if (centerName === this._lastName) return;
        // Clear and Reset
        this._lastName = centerName as celestial;
        this._cards.length = this._mainData.length = this._descData.length =
            this._astData.length = this._phyData.length = this._strData.length = 0;
        // Main Parameters
        this._assembler = this._mainData;
        if (inStar || inBlackhole) {
            const { diam, ab, cst, dist, mag, abs, ra, dec,
                brc, brs, lon, spec, lum, cls, mul, desc, physical } = config as starConfig;
            const { date, orbiter, swz, csr, evl } = config as blackHoleConfig;
            const { fid, HD, HIP } = (visit.center as Star).precise.config as cstStarConfig;
            const { name, cname } = (visit.center as Star).precise.belong as constellationConfig;
            const rat = 1e8;
            this._add('categories@' + cat, 'cat')
                ._add(inStar ? ab : null, 'ab', { en: `${cst}${ab}`, cn: `${cname}${ab}` })
                ._add(inStar ? fid : null, 'fid')
                ._add(HD, 'hd')
                ._add(HIP, 'hip')
                ._add(cst, 'cst', { en: name, cn: cname })
                ._add(inStar ? diam : null, 'diam', `${(diam * 1e8).toFixed(0)} km`)
                ._add(swz, 'swz', `${swz.toFixed(0)} km`)
                ._add(csr, 'csr', `${(csr * 1e8).toFixed(0)} km`)
                ._add(dist, 'dist', { en: `${dist} lightyear`, cn: `${dist} 光年` })
                ._add(spec, 'spec')
                ._add(date, 'date')
                ._add(brc, 'brc')
                ._add(brs, 'brs')
            // Other Data
            this._reloadDesc(desc);
            this._reloadAst(orbiter, rat);
            this._reloadAst4Star(mag, abs, ra, dec, lon, lum, cls, mul, evl);
            this._reloadPhy(physical);
            this._reloadStr();
        } else if (unbelt) {
            const { nick, diam, date, desc, disc, orbiter, physical } = config;
            const { belongs, seq, sphere, aid } = config as dsmConfig;
            const { ksn } = config as planetConfig;
            const rat = cat === 'satellite' ? 1e6 : 1e8;
            this._add('categories@' + cat, 'cat')
                ._add(nick, 'nick')
                ._add(belongs, 'belongs')
                ._add(seq, 'seq')
                ._add(aid, 'aid')
                ._add(diam, 'diam', `${(diam * rat).toFixed(0)} km`)
                ._add(sphere, 'sphere')
                ._add(date, 'date')
                ._add(disc, 'disc')
                ._add(ksn, 'ksn');
            // Other Data
            this._reloadDesc(desc);
            this._reloadAst(orbiter, rat);
            this._reloadPhy(physical);
            this._reloadStr();
        } else {
            const { max, total, weight, distances, desc }
                = (visit.center as Belts)?.configs[centerName] ?? {};
            this._add('categories@' + cat, 'cat')
                ._add(max, 'max')
                ._add(total, 'total')
                ._add(weight, 'weight')
                ._add(distances, 'distances');
            // Other Data
            this._reloadDesc(desc);
            this._reloadStr();
        }
        this._updateRender();
    }

    private _reloadDesc(desc: [i18nKey, num.int]): void {
        this._descData.push({ tag: 'overview' });
        if (notEmptyArr(desc)) {
            this._assembler = this._descData;
            this._cards.push(this._descData);
            const [key, num] = desc;
            for (let i = 0; i < num; i++) {
                this._descData.push({ value: key + '_' + i });
            }
        }
    }

    private _reloadAst(orbiter: orbiterConfig, rat: num.ratio): void {
        this._astData.push({ tag: 'astronomical' });
        if (!orbiter) return;
        const { orbital, rotate } = orbiter;
        this._assembler = this._astData;
        this._cards.push(this._astData);
        if (orbital) {
            const { radius, lon, obliquity, eccentricity, period } = orbital;
            this._add(radius, 'radius', `${(radius * rat).toFixed(0)} km`)
                ._add(lon, 'lon', `${lon}°`)
                ._add(obliquity, 'obl', `${obliquity}°`)
                ._add(eccentricity, 'ecc',)
                ._add(period, 'prd');
        }
        if (rotate) {
            const { nra, nd, obliquity, period } = rotate;
            this._add(nra, 'nra', `${nra}°`)
                ._add(nd, 'nd', `${nd}°`)
                ._add(obliquity, '_obl', `${obliquity}°`)
                ._add(period, '_prd');
        }
    }

    private _reloadAst4Star(mag?: magnitude, abs?: TypeOrArr<magnitude>,
        ra?: string, dec?: string, lon?: string, lum?: string, cls?: string, mul?: string, evl?: string): void {
        this._astData.push({ tag: 'astronomical' });
        this._assembler = this._astData;
        this._cards.push(this._astData);
        this._add(mag, 'mag')
            ._add(isArr(abs) ? abs.join(' + ') : abs, 'abs')
            ._add(ra, 'ra')
            ._add(dec, 'dec')
            ._add(lon, 'lon')
            ._add(evl, 'evl')
            ._add(lum ? 'lumins@' + lum : null, 'lum')
            ._add(cls ? 'specs@' + cls : null, 'cls');
        if (mul) {
            const [en, cn] = mul.split('&');
            this._add(mul, 'mul', { en, cn });
        }
    }

    private _reloadPhy(physical: physical): void {
        this._phyData.push({ tag: 'physical' });
        if (physical) {
            this._assembler = this._phyData;
            this._cards.push(this._phyData);
            const arr = physical.split(',');
            arr.forEach(pair => {
                const [key, value] = pair.split(':');
                this._add(key, key as tag, value);
            });
        }
    }

    private _reloadStr(): void {
        this._assembler = this._strData;
        this._cards.push(this._strData);
        this._strData.push({ tag: 'structure' }, { value: 'todos@dev' });
    }


    private _add(value: any, tag: tag, decoValue?: string | i18nConfig): this {
        if (!isNullish(value)) this._assembler.push({ tag, value: decoValue ?? (value + '') })
        return this;
    }

    private _updateRender(): void {
        this.title.string = 'celestial@' + this._lastName;
        this.mainList.updateList(this._mainData);
        this._showDataAt(0);
        this._updateListLayout(false);
    }

    protected onHide(): void {
        this.node.removeFromParent();
    }

    private _showDataAt(idx: num.idx): void {
        this.arrowLeft.active = idx > 0;
        this.arrowRight.active = idx < this._cards.length - 1;
        const data = this._cards[idx];
        this.cardList.updateList(data);
        this._showAt = idx;
    }

    private _lastName: celestial;
    private _mainData: IIntroLineData[] = [];
    private _descData: IIntroLineData[] = [];
    private _astData: IIntroLineData[] = [];
    private _phyData: IIntroLineData[] = [];
    private _strData: IIntroLineData[] = [];
    private _cards: IIntroLineData[][] = [];
    private _showAt: num.idx = 0;
    private _assembler: IIntroLineData[] = [];
}

const { Transform } = View;